#include "onps.h"
#include <nxos.h>

#define DHCP_REQ_ADDR_EN    0

#define NETIF_ETH_NAME      "eth0"

#define PRIMARY_DNS_DEFAULT   "1.2.4.8"
#define SECONDARY_DNS_DEFAULT "8.8.8.8"

static PST_NETIF l_pstNetifEth = NULL;
static HMUTEX l_hMtxEthSend = INVALID_HMUTEX;
static UCHAR lr_ubaMacAddr[6] = {0};
static NX_Solt l_ethSolt = NX_SOLT_INVALID_VALUE;
static UCHAR l_sendBuf[1500];
static UCHAR l_recvBuf[1500];

INT EthSend(SHORT sBufListHead, UCHAR *pubErr);
void EthRecv(void);

NX_U32 __thread_ethernet_ii_recv(void *arg)
{
    thread_ethernet_ii_recv(arg);
    return 0;
}

NX_U32 EthRecvThread(void *arg)
{
  while (1)
  {
    EthRecv();
  }
  return 0;
}

static void start_thread_ethernet_ii_recv(void *pvParam)
{
  NX_Solt tid = NX_ThreadCreate(NX_NULL, __thread_ethernet_ii_recv, pvParam, 0);
  if(tid == -1)
    printf("The creation of task thread_ethernet_ii_recv failed\r\n");
  tid = NX_ThreadCreate(NX_NULL, EthRecvThread, pvParam, 0);
  if(tid == -1)
    printf("The creation of task thread_ethernet_ii_recv failed\r\n");
}

BOOL EthInit(void)
{
  EN_ONPSERR enErr;

  l_hMtxEthSend = os_thread_mutex_init();
  if (INVALID_HMUTEX == l_hMtxEthSend) {
    return FALSE;
  }

    l_ethSolt = NX_DeviceOpen("pcnet32", 0);
    if (NX_SOLT_INVALID_VALUE == l_ethSolt) {
        os_thread_mutex_uninit(l_hMtxEthSend);
        return FALSE;
    }

    /* get mac addr */
    if (NX_DeviceControl(l_ethSolt, 1, lr_ubaMacAddr)) {
        NX_DeviceClose(l_ethSolt);
        os_thread_mutex_uninit(l_hMtxEthSend);
        return FALSE;
    }

#if !DHCP_REQ_ADDR_EN
  ST_IPV4 stIPv4;
  stIPv4.unAddr = inet_addr("192.168.0.200");
  stIPv4.unSubnetMask = inet_addr("255.255.255.0");
  stIPv4.unGateway = inet_addr("192.168.0.1");
  stIPv4.unPrimaryDNS = inet_addr(PRIMARY_DNS_DEFAULT);
  stIPv4.unSecondaryDNS = inet_addr(SECONDARY_DNS_DEFAULT);
  stIPv4.unBroadcast = broadcast_addr(stIPv4.unAddr, stIPv4.unSubnetMask);
  l_pstNetifEth = ethernet_add(NETIF_ETH_NAME, lr_ubaMacAddr, &stIPv4, EthSend, start_thread_ethernet_ii_recv, &l_pstNetifEth, &enErr);
#else
  l_pstNetifEth = ethernet_add(NETIF_ETH_NAME, lr_ubaMacAddr, NULL, EthSend, start_thread_ethernet_ii_recv, &l_pstNetifEth, &enErr);
#endif

  if(!l_pstNetifEth)
  {
#if SUPPORT_PRINTF
    printf("ethernet_add() failed, %s\r\n", onps_error(enErr));
#endif
    return FALSE;
  }

#if DHCP_REQ_ADDR_EN
  while(TRUE)
  {
    if(dhcp_req_addr(l_pstNetifEth, &enErr))
    {
    #if SUPPORT_PRINTF
      printf("dhcp request ip address successfully.\r\n");
    #endif
      break;
    }
    else
    {
    #if SUPPORT_PRINTF
      printf("dhcp request ip address failed, %s\r\n", onps_error(enErr));
    #endif
      os_sleep_secs(6);
    }
  }
#endif //* #if DHCP_REQ_ADDR_EN
  return TRUE;
}

INT ETH_TxPktChainMode(USHORT usFramLen, SHORT sBufListHead)
{
    buf_list_merge_packet(sBufListHead, (UCHAR *)l_sendBuf);
    /**
     * send to eth device
     */
    if (!NX_DeviceWrite(l_ethSolt, l_sendBuf, 0, usFramLen))
        return -1;
    return (INT)usFramLen;
}

INT EthSend(SHORT sBufListHead, UCHAR *pubErr)
{
  UINT unEthPacketLen = buf_list_get_len(sBufListHead);

  INT nRtnVal, nTryNum = 0;
  do
  {
    os_thread_mutex_lock(l_hMtxEthSend);
    {
        nRtnVal = ETH_TxPktChainMode((USHORT)unEthPacketLen, sBufListHead);
    }
    os_thread_mutex_unlock(l_hMtxEthSend);
  } while(nRtnVal < 0 && nTryNum++ < 10);

  if(nRtnVal < 0)
  {
      if(pubErr)
        *((EN_ONPSERR *)pubErr) = ERRNETIFSEND;
  }

  return (INT)nRtnVal;
}

void EthRecv(void)
{
  UINT unFrameLen = 0;
  int try_count = 0;

__lblGetNext:
    unFrameLen = NX_DeviceRead(l_ethSolt, l_recvBuf, 0, 1500);
    if (!unFrameLen) {
      try_count++;
      if (try_count > 50) {
        NX_ThreadSleep(50);
      }
      goto __lblGetNext;
    }
    try_count = 0;
    if(l_pstNetifEth)
    {
      UCHAR *pubPacket;
      EN_ONPSERR enErr;
      pubPacket = (UCHAR *)buddy_alloc(sizeof(ST_SLINKEDLIST_NODE) + unFrameLen, &enErr);
      if(pubPacket)
      {
        //* �������ݵ���������
        PST_SLINKEDLIST_NODE pstNode = (PST_SLINKEDLIST_NODE)pubPacket;
        pstNode->uniData.unVal = unFrameLen;
        memcpy(pubPacket + sizeof(ST_SLINKEDLIST_NODE), (UCHAR *)l_recvBuf, unFrameLen);
        ethernet_put_packet(l_pstNetifEth, pstNode);
      }
      else
      {
      #if SUPPORT_PRINTF && DEBUG_LEVEL
        printf("<EIRQ> %s\r\n", onps_error(enErr));
      #endif
      }
    }
  goto __lblGetNext;
}
